<?php

namespace youmbe\phpword\widgets;

use Yii;
use yii\base\Arrayable;
use yii\base\InvalidConfigException;
use yii\base\Model;
use yii\helpers\ArrayHelper;
use yii\helpers\Inflector;
use PhpOffice\PhpWord\Style\TablePosition;
use PhpOffice\PhpWord\Shared\Converter;

/**
 * DetailView displays the detail of a single word data [[model]].
 *
 * @author emhome <emhome@163.com>
 * @since 1.0
 */
class MutilDetailView extends BaseTableView {

    /**
     * @var array|object the data model whose details are to be displayed. This can be a [[Model]] instance,
     * an associative array, an object that implements [[Arrayable]] interface or simply an object with defined
     * public accessible non-static properties.
     */
    public $model;

    /**
     * @var array a list of attributes to be displayed in the detail view. Each array element
     * represents the specification for displaying one particular attribute.
     *
     * An attribute can be specified as a string in the format of `attribute`, `attribute:format` or `attribute:format:label`,
     * where `attribute` refers to the attribute name, and `format` represents the format of the attribute. The `format`
     * is passed to the [[Formatter::format()]] method to format an attribute value into a displayable text.
     * Please refer to [[Formatter]] for the supported types. Both `format` and `label` are optional.
     * They will take default values if absent.
     *
     * An attribute can also be specified in terms of an array with the following elements:
     *
     * - `attribute`: the attribute name. This is required if either `label` or `value` is not specified.
     * - `label`: the label associated with the attribute. If this is not specified, it will be generated from the attribute name.
     * - `value`: the value to be displayed. If this is not specified, it will be retrieved from [[model]] using the attribute name
     *   by calling [[ArrayHelper::getValue()]]. Note that this value will be formatted into a displayable text
     *   according to the `format` option. Since version 2.0.11 it can be defined as closure with the following
     *   parameters:
     *
     *   ```php
     *   function ($model, $widget)
     *   ```
     *
     *   `$model` refers to displayed model and `$widget` is an instance of `DetailView` widget.
     *
     * - `format`: the type of the value that determines how the value would be formatted into a displayable text.
     *   Please refer to [[Formatter]] for supported types and [[Formatter::format()]] on how to specify this value.
     * - `visible`: whether the attribute is visible. If set to `false`, the attribute will NOT be displayed.
     * - `contentOptions`: the HTML attributes to customize value tag. For example: `['class' => 'bg-red']`.
     *   Please refer to [[\yii\helpers\BaseHtml::renderTagAttributes()]] for the supported syntax.
     * - `captionOptions`: the HTML attributes to customize label tag. For example: `['class' => 'bg-red']`.
     *   Please refer to [[\yii\helpers\BaseHtml::renderTagAttributes()]] for the supported syntax.
     */
    public $attributes;

    /**
     * @var boolean 是否自动追加冒号
     */
    public $groupAttributes = [];

    /**
     * @var array|string|null 单元格样式
     * 
     * `alignment`. Supports all alignment modes since 1st Edition of ECMA-376 standard up till ISO/IEC 29500:2012.
     * See \PhpOffice\PhpWord\SimpleType\JcTable and \PhpOffice\PhpWord\SimpleType\Jc class constants for possible values.
     * `bgColor`. Background color, e.g. ‘9966CC’.
     * `border(Top|Right|Bottom|Left)Color`. Border color, e.g. ‘9966CC’.
     * `border(Top|Right|Bottom|Left)Size`. Border size in twip.
     * `cellMargin(Top|Right|Bottom|Left)`. Cell margin in twip.
     * `indent`. Table indent from leading margin. Must be an instance of \PhpOffice\PhpWord\ComplexType\TblWidth.
     * `width`. Table width in Fiftieths of a Percent or Twentieths of a Point.
     * `unit`. The unit to use for the width. One of \PhpOffice\PhpWord\SimpleType\TblWidth. Defaults to auto.
     * `layout`. Table layout, either fixed or autofit See \PhpOffice\PhpWord\Style\Table for constants.
     * `cellSpacing` Cell spacing in twip
     * `position` Floating Table Positioning, see below for options
     * `bidiVisual` Present table as Right-To-Left
     */
    public $tableStyle = [
        'width' => 100
    ];

    /**
     * @var array|string|null 单元格样式
     */
    public $position = [
        'vertAnchor' => TablePosition::VANCHOR_PAGE,
        'horzAnchor' => TablePosition::HANCHOR_PAGE,
        'tblpXSpec' => TablePosition::XALIGN_CENTER,
        'tblpYSpec' => TablePosition::YALIGN_CENTER,
    ];

    /**
     * @var boolean 是否自动追加冒号
     */
    public $autoAfterColon = false;

    /**
     * @var string|null 冒号
     */
    public $colon;

    /**
     * @var array|null 标签选项
     */
    public $captionOptions;

    /**
     * @var array|null 内容选项
     */
    public $contentOptions;

    /**
     * @var array|string|null 单元格样式
     */
    public $cellStyle = [
        'borderColor' => '000000',
        'borderSize' => 2,
        'unit' => \PhpOffice\PhpWord\SimpleType\TblWidth::PERCENT,
    ];

    /**
     * Initializes the detail view.
     * This method will initialize required property values.
     */
    public function init() {
        parent::init();
        if ($this->model === null) {
            throw new InvalidConfigException('Please specify the "model" property.');
        }
        $this->normalizeAttributes();
    }

    public $maxGroupColumns = 1;

    /**
     * Renders the detail view.
     * This is the main entry of the whole detail view rendering.
     */
    public function renderLayout() {
        $height = ArrayHelper::getValue($this->rowOptions, 'height');
        if ($height) {
            $height = Converter::pointToTwip($height);
        }
        $table = $this->layout;
//        $table->addRow();
//        $styleCell = array(
//            'borderColor' => '000000',
//            'borderSize' => 2,
//            'unit' => 'pct',
//            'gridSpan' => 2,
//        );
//
//        $table->addCell(200, $styleCell)->addText('PHP点点通');
//        $table->addCell(100)->addText('http://www.phpddt.com');
//        $table->addRow();
//        $table->addCell(100)->addText('PHP');
//        $table->addCell(100)->addText('python');
//        $table->addCell(100)->addText('java');

        foreach ($this->attributes as $group) {
            $row = $table->addRow($height, $this->filterRowStyles($this->rowOptions));
            foreach ($group as $attribute) {
                $this->renderCaptionCell($row, $attribute);
                $this->renderContentCell($row, $attribute);
            }
        }
        $footerRow = $table->addRow($height, $this->filterRowStyles($this->rowOptions));
        $footerRow->addCell(100, [
            'borderColor' => '000000',
            'borderSize' => 2,
            'unit' => 'pct',
            'gridSpan' => 5,
        ])->addText('人员信息登记表（含公司陪同人员）');


        $dataProvider = new \yii\data\ActiveDataProvider([
            'query' => $this->model->getStaffs(),
            'pagination' => false
        ]);
        $attributes = [
            'realname',
            'company_name',
            'position',
            'mobile',
        ];
        foreach ($dataProvider->getModels() as $index => $staff) {
            if (!$index) {
                $headerRow = $table->addRow($height, $this->filterRowStyles($this->rowOptions));
                $headerRow->addCell(20, [
                    'borderColor' => '000000',
                    'borderSize' => 2,
                    'unit' => 'pct',
                ])->addText('序号');
                foreach ($attributes as $attribute) {
                    $headerRow->addCell(20, [
                        'borderColor' => '000000',
                        'borderSize' => 2,
                        'unit' => 'pct',
                    ])->addText($staff->getAttributeLabel($attribute));
                }
            }
            $contentRow = $table->addRow($height, $this->filterRowStyles($this->rowOptions));
            $contentRow->addCell(20, [
                'borderColor' => '000000',
                'borderSize' => 2,
                'unit' => 'pct',
            ])->addText($index + 1);
            foreach ($attributes as $attribute) {
                $contentRow->addCell(20, [
                    'borderColor' => '000000',
                    'borderSize' => 2,
                    'unit' => 'pct',
                ])->addText($staff->$attribute);
            }
        }





//
//
//
//
//        GridView::widget([
//            'options' => [
//                'unit' => $this->unit,
//            ],
//            'paragraphStyle' => [
//                'indentation' => [
//                    'firstLine' => 0,
//                ],
//                'indent' => 0,
//                'lineHeight' => 1,
//            ],
//            'section' => $this->section,
//            'dataProvider' => new \yii\data\ActiveDataProvider([
//                'query' => $this->model->getStaffs(),
//                'pagination' => false
//            ]),
//            'columns' => [
//                [
//                    'label' => '序号',
//                    'headerOptions' => [
//                        'width' => 15,
//                    ],
//                ],
//                [
//                    'attribute' => 'realname',
//                    'headerOptions' => [
//                        'width' => 15,
//                    ],
//                ],
//                [
//                    'attribute' => 'company_name',
//                    'headerOptions' => [
//                        'width' => 30,
//                    ],
//                ],
//                [
//                    'attribute' => 'position',
//                    'headerOptions' => [
//                        'width' => 10,
//                        'align' => 'right',
//                    ],
//                    'contentOptions' => [
//                        'align' => 'right'
//                    ]
//                ],
//                [
//                    'attribute' => 'mobile',
//                    'headerOptions' => [
//                        'width' => 10,
//                        'align' => 'right',
//                    ],
//                    'contentOptions' => [
//                        'align' => 'right'
//                    ]
//                ],
//            ],
//        ]);
    }

    /**
     * Renders a single attribute.
     * @param \PhpOffice\PhpWord\Element\Row $row the specification of the attribute to be rendered.
     * @param array $attribute the specification of the attribute to be rendered.
     * @param int $index the zero-based index of the attribute in the [[attributes]] array
     * @return string the rendering result
     */
    public function renderCaptionCell($row, $attribute) {
        $captionOptions = ArrayHelper::getValue($attribute, 'captionOptions');
        $fontStyle = $this->mergeStyleArray('fontStyle', $this->rowOptions, $this->captionOptions, $captionOptions);
        if ($fontStyle) {
            $captionOptions['fontStyle'] = $fontStyle;
        }
        $paragraphStyle = $this->mergeStyleArray('paragraphStyle', $this->rowOptions, $this->captionOptions, $captionOptions);
        if ($paragraphStyle) {
            $captionOptions['paragraphStyle'] = $paragraphStyle;
        }

        $label = $attribute['label'];
        if ($this->autoAfterColon !== false) {
            $label = rtrim($label, $this->colonChar) . $this->colonChar;
        }
        $this->renderCell($row, $label, $captionOptions);
    }

    /**
     * Renders a single attribute.
     * @param \PhpOffice\PhpWord\Element\Row $row the specification of the attribute to be rendered.
     * @param array $attribute the specification of the attribute to be rendered.
     * @param int $index the zero-based index of the attribute in the [[attributes]] array
     * @return string the rendering result
     */
    public function renderContentCell($row, $attribute) {
        $contentOptions = ArrayHelper::getValue($attribute, 'contentOptions');
        $fontStyle = $this->mergeStyleArray('fontStyle', $this->rowOptions, $this->contentOptions, $contentOptions);
        if ($fontStyle) {
            $contentOptions['fontStyle'] = $fontStyle;
        }
        $paragraphStyle = $this->mergeStyleArray('paragraphStyle', $this->rowOptions, $this->contentOptions, $contentOptions);
        if ($paragraphStyle) {
            $contentOptions['paragraphStyle'] = $paragraphStyle;
        }
        $value = $this->formatter->format($attribute['value'], $attribute['format']);
        $this->renderCell($row, $value, $contentOptions);
    }

    /**
     * Normalizes the attribute specifications.
     * @throws InvalidConfigException
     */
    public function getColonChar() {
        if ($this->colon) {
            return $this->colon;
        }
        return $this->language == 'zh-CN' ? '：' : ':';
    }

    /**
     * Normalizes the attribute specifications.
     * @throws InvalidConfigException
     */
    protected function normalizeAttributes() {
        if ($this->attributes === null) {
            if ($this->model instanceof Model) {
                $this->attributes = $this->model->attributes();
            } elseif (is_object($this->model)) {
                $this->attributes = $this->model instanceof Arrayable ? array_keys($this->model->toArray()) : array_keys(get_object_vars($this->model));
            } elseif (is_array($this->model)) {
                $this->attributes = array_keys($this->model);
            } else {
                throw new InvalidConfigException('The "model" property must be either an array or an object.');
            }
            sort($this->attributes);
        }

        $maxColumns = 1;
        foreach ($this->attributes as $i => $row) {
            $rowAttributes = [];
            $maxColumns = max($maxColumns, count($row));
            foreach ($row as $attribute) {
                if (is_string($attribute)) {
                    if (!preg_match('/^([^:]+)(:(\w*))?(:(.*))?$/', $attribute, $matches)) {
                        throw new InvalidConfigException('The attribute must be specified in the format of "attribute", "attribute:format" or "attribute:format:label"');
                    }
                    $attribute = [
                        'attribute' => $matches[1],
                        'format' => isset($matches[3]) ? $matches[3] : 'text',
                        'label' => isset($matches[5]) ? $matches[5] : null,
                    ];
                }

                if (!is_array($attribute)) {
                    throw new InvalidConfigException('The attribute configuration must be an array.');
                }

                if (isset($attribute['visible']) && !$attribute['visible']) {
                    unset($this->attributes[$i]);
                    continue;
                }

                if (!isset($attribute['format'])) {
                    $attribute['format'] = 'text';
                }
                if (isset($attribute['attribute'])) {
                    $attributeName = $attribute['attribute'];
                    if (!isset($attribute['label'])) {
                        $attribute['label'] = $this->model instanceof Model ? $this->model->getAttributeLabel($attributeName) : Inflector::camel2words($attributeName, true);
                    }
                    if (!array_key_exists('value', $attribute)) {
                        $attribute['value'] = ArrayHelper::getValue($this->model, $attributeName);
                    }
                } elseif (!isset($attribute['label']) || !array_key_exists('value', $attribute)) {
                    throw new InvalidConfigException('The attribute configuration requires the "attribute" element to determine the value and display label.');
                }

                if ($attribute['value'] instanceof \Closure) {
                    $attribute['value'] = call_user_func($attribute['value'], $this->model, $this);
                }
                $rowAttributes[] = $attribute;
            }
            $this->attributes[$i] = $rowAttributes;
        }
        $this->maxGroupColumns = $maxColumns;
    }

}
